/**
  * @(#)Course.java
  *
  * Class to represent a Course. A course corresponds to a specific course
  * number at a specific university. A course may contain multiple sections
  * which are the individual registration units for that class.e
  *
  * @author Course Scheduler Team
  * 
  * @license GNU General Public License version 3 (GPLv3)
  *
  * This file is part of Course Scheduler, an open source, cross platform
  * course scheduling tool, configurable for most universities.
  *
  * Copyright (C) 2010-2012 Course Scheduler Team
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  * 
  */
package com.pollicitus.scheduler.model;

import java.util.Collection;
import java.util.HashSet;

import com.pollicitus.scheduler.model.ClassLevel;
import com.pollicitus.scheduler.model.Course;
import com.pollicitus.scheduler.model.Section;


/**
 * Class to represent a Course. A course corresponds to a specific course
 * number at a specific university. A course may contain multiple sections
 * which are the individual registration units for that class. * 
 * 
 * @author Course Scheduler Team
 *
 */
public class Course implements Comparable<Course>{

	/**
	 * The most recent revision in which this file was changed in the source control system
	 */
	public static final String _revision = "$LastChangedRevision: 539 $";
	
	/**
	 * The date on which this file was last changed and submitted to source control
	 */
	public static final String _date = "$LastChangedDate: 2011-11-19 23:14:16 -0500 (Sat, 19 Nov 2011) $";
	
	/**
	 * The user which last changed the file and committed the change to source control
	 */
	public static final String _author = "$LastChangedBy: mike@pollicitus.com $";
	
	/**
	 * The URL which can be used to access this specific file within the source control system
	 */
	public static final String _headURL = "$HeadURL: https://courseschedulerx.googlecode.com/svn/trunk/course-scheduler/course-scheduler-core/src/main/java/com/pollicitus/scheduler/model/Course.java $";
	
	/**
	 * The source control file ID, comprised of the file name, latest revision, last changed date, and submitting user.
	 */
	public static final String _id = "$Id: Course.java 539 2011-11-20 04:14:16Z mike@pollicitus.com $";
	
	/**
	 * department = the department the course is a part of
	 * courseID = the course code
	 * name = the name of the course
	 * description = description of the course
	 * preReqs = the list of courses that must be completed before this course
	 * coReqs = the list of courses that must be completed at the same time as this course
	 * sections = the list of registration sections for this course
	 * credits = a string representing the credit value of the course
	 * grade = the grading method used in the course
	 * level = the level of the course (eg. Undergraduate, Graduate)
	 * termName = the string description of the registration term
	 * university = the university the course is offered at
	 */
	private String department;
	private String courseID;
	private String name;
	private String description;
	private Collection<Course> preReqs;
	private Collection<Course> coReqs;
	private Collection<Section> sections;
	private ClassLevel level;
	private String termName;
	private String university;
	
	/**
	 * Default constructor to prepare the private variables of the course
	 */
	public Course() {
		this.preReqs = new HashSet<Course>();
		this.coReqs = new HashSet<Course>();
		this.sections = new HashSet<Section>();
	}

	/**
	 * Constructor for the Course based on the courseID. This uniquely 
	 * defines the course for a given university. The combination of the
	 * university and the course id are the globally unique identifiers 
	 * for the course.
	 * 
	 * @param courseID the course identifier which uniquely defines the course
	 * within a university
	 */
	public Course(String courseID) {
		this();
		this.courseID = courseID;
	}
	
	/**
	 * Add a course to the prerequisite list for this course
	 * 
	 * @param course a prerequisite for this course
	 */
	public void addPreReq(Course course) {
		if(!this.preReqs.contains(course)) {
			this.preReqs.add(course);
		}else {
			//TODO how to handle if prereq already exists?
			//probably should just ignore silently
		}
	}
	
	/**
	 * Add a course to the corequisite list for this course
	 * 
	 * @param course a corequisite for this course
	 */
	public void addCoReq(Course course) {
		if(!this.coReqs.contains(course)) {
			this.coReqs.add(course);
		}else {
			//TODO how to handle if coreq already exists?
			//probably ignore silently
		}
	}
	
	/**
	 * Add a section to this course instance. A section is the uniquely
	 * registerable segment of this course.
	 * 
	 * @param sectionID the unique identifier for the section within the course
	 */
	public void addSection(Section sectionID) {
		if(!this.sections.contains(sectionID)) {
			this.sections.add(sectionID);
		}else {
			//TODO how to handle if section already exists?
			//probably ignore silently
		}
	}
	
	/**
	 * Return the array of sections available when registering for this course.
	 * 
	 * @return the available sections
	 */
	public Section[] getSections() {
		return this.sections.toArray(new Section[this.sections.size()]);
	}
	
	/**
	 * Create a new section for this course and add it to the list of
	 * available sections
	 * 
	 * @param sectionID the section id to use for the new section
	 * @return a new section based on this course
	 */
	public Section createSection(String sectionID) {
		Section toAdd = new Section();
		
		//set the course specific fields as the parent
		toAdd.setParent(this);
		
		//make the section unique and add to the list of sections
		toAdd.setSectionID(sectionID);
		this.addSection(toAdd);
		
		return toAdd;
	}
	
	/**
	 * Return the course ID that uniquely identifies this course within
	 * a universities course list.
	 * 
	 * @return the courseID of this Course object
	 */
	public String getCourseID() {
		return courseID;
	}

	/**
	 * Return the department which teaches the course
	 * 
	 * @return the department which teaches the course
	 */
	public String getDepartment() {
		return department;
	}

	/**
	 * Return the course description as downloaded. This is usually a short 
	 * blurb about the course based on the university's course list.
	 * 
	 * @return the description of the course
	 */
	public String getDescription() {
		return description;
	}

	/**
	 * Return the course name assigned to this course
	 * 
	 * @return the name of this course
	 */
	public String getName() {
		return name;
	}

	/**
	 * Set the course ID for this course instance
	 * 
	 * @param courseID the courseID to use
	 */
	public void setCourseID(String courseID) {
		this.courseID = courseID;
	}

	/**
	 * Set the course department for this course instance
	 * 
	 * @param department the department to use
	 */
	public void setDepartment(String department) {
		this.department = department;
	}

	/**
	 * Set the course description for this course instance
	 * 
	 * @param description the description to use
	 */
	public void setDescription(String description) {
		this.description = description;
	}

	/**
	 * Set the course name for this course instance
	 * 
	 * @param name the name to use
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Set the course level corresponding to the course registration level
	 * 
	 * @return the registration level of the course
	 */
	public ClassLevel getLevel() {
		return level;
	}

	/**
	 * Set the course registration level
	 * 
	 * @param level the registration level to use
	 */
	public void setLevel(ClassLevel level) {
		this.level = level;
	}

	/* (non-Javadoc)
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 * 
	 * Note: Semantics differ from Course.equals
	 */
	public int compareTo(Course arg0) {
		return getCourseID().compareTo(arg0.getCourseID());
	}

	/**
	 * Return the registration term for which the course is defined
	 * 
	 * @return the registration term for the course
	 */
	public String getTerm() {
		return termName;
	}

	/**
	 * Set the registration term for the course
	 * 
	 * @param termName the registration term to use
	 */
	public void setTerm(String term) {
		this.termName = term;
	}

	/**
	 * Return the university name for this course instance
	 * 
	 * @return the name of the university which is offering the course
	 */
	public String getUniversity() {
		return university;
	}

	/**
	 * Set the course university name
	 * 
	 * @param university the university to use
	 */
	public void setUniversity(String university) {
		this.university = university;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object other){
		Course course = (Course)other;
		
		//courses are identical if they have the same ID and are for the same 
		//University in the same registration term
		return course.getUniversity().compareTo(this.getUniversity()) == 0 &&
				course.getTerm().compareTo(this.getTerm()) == 0 && 
				course.getCourseID().compareTo(this.getCourseID()) == 0;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode(){
		//create the hashcode by XORing the fields that make the Course unique
		return this.getUniversity().hashCode() ^
				this.getTerm().hashCode() ^ 
				this.getCourseID().hashCode();
	}
}
